I am new to Xamarin and the MVVM pattern and I have a simple application that should display contacts in a list.
Now my view displays the contacts lastname and its number. Okay, great! Now I would like to have Lastname and Surname displayed. Sure I could modify my model to hold a property of something called public string FullName
and fill that. But I guess thats not in the spirit of the pattern, right?
Where should I reflect something like this without violating the pattern? Only within view and the XAML file by using something like <MultiBinding />
? Or should my ViewModel hold additional properties?
This is my code:
Model:
public class Contact
{
public string Id { get; set; }
public string Surname { get; set; }
public string Lastname { get; set; }
public string Number { get; set; }
}
ViewModel:
public class ContactsViewModel : ViewModelBase
{
public ObservableCollection<Contact> Contacts { get; set; }
public Command LoadContacts { get; set; }
public ContactsViewModel()
{
this.Title = "List of contacts";
Contacts = new ObservableCollection<Contact>();
LoadContacts = new Command(async () => await LoadContactsFromDataStore());
}
private async Task LoadContactsFromDataStore()
{
var contacts = await ContactDataStore.GetItemsAsync(true);
foreach (var contact in contacts)
{
Contacts.Add(contact);
}
}
}
And my base class
public abstract class ViewModelBase : INotifyPropertyChanged
{
public string Title { get; set; }
public IContactDataStore<Contact> ContactDataStore => DependencyService.Get<IContactDataStore<Contact>>();
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
View:
<ContentPage.ToolbarItems>
<ToolbarItem Text="New Contact" Clicked="AddContact_Clicked"/>
</ContentPage.ToolbarItems>
<StackLayout>
<ListView x:Name="ContactsListView"
ItemsSource="{Binding Contacts}"
VerticalOptions="FillAndExpand"
HasUnevenRows="True"
ItemSelected="OnItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="10">
<Label Text="{Binding Lastname}" FontSize="16"></Label>
<Label Text="{Binding Number}" FontSize="13"></Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
Code behind:
[DesignTimeVisible(false)]
public partial class ContactsPage : ContentPage
{
private readonly ContactsViewModel contactsViewModel;
public ContactsPage()
{
InitializeComponent();
BindingContext = contactsViewModel = new ContactsViewModel();
}
private async void OnItemSelected(object sender, SelectedItemChangedEventArgs args)
{
if (!(args.SelectedItem is Contact contact))
return;
await Navigation.PushAsync(new ContactDetailPage(new ContactDetailViewModel(contact)));
ContactsListView.SelectedItem = null;
}
private async void AddContact_Clicked(object sender, EventArgs e)
{
throw new NotImplementedException();
}
protected override void OnAppearing()
{
base.OnAppearing();
if (contactsViewModel.Contacts.Count == 0)
{
contactsViewModel.LoadContacts.Execute(null);
}
}
}